package com.android;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.app.ListActivity;
import android.app.ProgressDialog;
import android.content.Context;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;

import com.android.data.ServerManager;
import com.android.entities.AgendaEntry;
import com.android.util.Time;

public class _ProgrammingActivity extends ListActivity {
	
	private ArrayList<String> categoriesList;
	private static int startTime;
	private static String categories;
	
	private Context mContext;
	private EntryAdapter mAdapter;
	
	private ProgressDialog m_ProgressDialog = null;
	private Runnable getData;
	private static Thread eventsThread;
	
	private JSONObject events;
	private ArrayList<AgendaEntry> eventsList;
	
	/** Called when the activity is first created. */
    @Override
    @SuppressWarnings("unchecked")
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
                
        mContext = this;
        eventsList = new ArrayList<AgendaEntry>();
        
        //mAdapter = new EntryAdapter(mContext, R.layout.row_schedule, eventsList);
        setListAdapter(mAdapter);
        
        //Get search filters
        Bundle mBundle = getIntent().getExtras();
        startTime = mBundle.getInt("hour") * 60 + mBundle.getInt("minute");
        this.categoriesList = (ArrayList<String>) mBundle.get("categories");
        
        categories = "";
        for (String s: categoriesList) {
        	categories += s + "|"; 
        }

        if (categories.length() > 0)
        	categories.substring(0, categories.length() - 1);
        
        //Get events
        getData = new Runnable(){
            public void run() {
            	retrieveEvents();
            }
        };
	    
        
        eventsThread =  new Thread(null, getData, "MagentoBackground");
        eventsThread.start();
	        m_ProgressDialog = ProgressDialog.show(mContext,    
	              "Por favor aguarde...", "Buscando eventos ...", true);

    }
    
	/**
	 * Groups and sorts events by their starting time.
	 * This method receives a JSONArray containing events represented by JSONObjects. Each event 
	 * must have a starting time. This events will be grouped according to the time span they 
	 * are in. For example, all events starting between 18:00 and 19:00 will be grouped together.   
	 * @throws JSONException 
	 * **/
	@SuppressWarnings({ "unchecked", "rawtypes" })
	private static JSONObject sortEvents(JSONArray eventsFromServer) throws JSONException {
		JSONObject sortedEvents = new JSONObject();
		
		//No events in a day
		if (eventsFromServer.length() == 0) {
			System.out.println("No events");
			return sortedEvents;
		}

		//Sorting events by starting time
		for (int i = 0; i < eventsFromServer.length(); i++) {
			//Get the JSONObject that represents an event
			JSONObject event = eventsFromServer.getJSONObject(i);

			//Gets Event startTime
			Time startTime = new Time(event.getString("startTime")); 

			//Gets Event startHour
			int startHour = startTime.getHour();
			
			//Groups events in a JSONArray. This JSONArray is stored in eventsGrouped indexed by startHour
			JSONArray tempArray = new JSONArray();
			String key = String.valueOf(startHour);
			if (sortedEvents.has(key)) {
				tempArray = sortedEvents.getJSONArray(key);
			}
			tempArray.put(event);
			
			sortedEvents.put(key, tempArray);
		}
		
		//Sorts events in a time span
		Iterator keysIterator = (Iterator) sortedEvents.keys();
		
		while (keysIterator.hasNext()) {
			String timeKey = (String) keysIterator.next();
			JSONArray tempArray = (JSONArray) sortedEvents.get(timeKey);
			
			ArrayList<AgendaEntry> tempList = new ArrayList<AgendaEntry>();			
			for (int i = 0; i < tempArray.length(); i++) {
				AgendaEntry entry = new AgendaEntry(tempArray.getJSONObject(i));
				tempList.add(entry);
			}
			
			Collections.sort(tempList, new Comparator() {    
	            public int compare(Object o1, Object o2) {    
	            	AgendaEntry c1 = (AgendaEntry) o1;    
	            	AgendaEntry c2 = (AgendaEntry) o2;
	                
	                Time time1 = new Time(c1.getStartTime());
	                Time time2 = new Time(c2.getStartTime());
	                
	                return Time.compare(time1, time2);
            	}  
			});
			
			tempArray = new JSONArray();
			for (int i = 0; i < tempList.size(); i++) {
				tempArray.put(tempList.get(i).toJSON());
			}						

			sortedEvents.put(timeKey, tempArray);
		}
		
		return sortedEvents;
	}

    private void retrieveEvents() {    	
    	try{    		
    		events = ServerManager.getEvents(mContext, startTime, categories);
    		eventsList = new ArrayList<AgendaEntry>();

    		if (events.has("events") && events.get("events") != null) {
				JSONObject eventsArray = sortEvents(events.getJSONArray("events"));
        	    eventsList = organizeSchedule(eventsArray, new Time(startTime));
			}

    	} catch (JSONException e) {
    		if (e.getMessage() != null)
    			android.util.Log.e("BACKGROUND_PROC", "message: " + e.getMessage());
    		e.printStackTrace();
    		
    	} catch (Exception e) {
    		if (e.getMessage() != null)
    			android.util.Log.e("BACKGROUND_PROC", "message: " +  e.getMessage());
            e.printStackTrace();
		}

    	runOnUiThread(returnRes);	

    }
    
    private Runnable returnRes = new Runnable() {

        public void run() {
            if(eventsList != null && eventsList.size() > 0){
            	mAdapter.notifyDataSetChanged();
            	
                for(int i = 0; i < eventsList.size(); i++)
                	mAdapter.add(eventsList.get(i));
            }

            m_ProgressDialog.dismiss();
        }
    };
    
	/**
	 * Organizes a schedule to the user based on some parameters given by the user.
	 * @param startTime The time from which the user wants a schedule.
	 * @param categories A list containing the categories to be included in the schedule. 
	 * @param maxDistance The maximum distance the user wants to travel
	 * @param maxCost The maximum amount of money the user wants to spend.
	 * **/
	public static ArrayList<AgendaEntry> organizeSchedule(JSONObject dayEvents, 
			Time startTime) throws JSONException {
		ArrayList<AgendaEntry> schedule = new ArrayList<AgendaEntry>();
		//HashSet<String> eventsAdded = new HashSet<String>(); 
		
		if (dayEvents.length() == 0)
			return schedule;
	
		//Generate schedule
		Time nextAvailableTime = startTime;
		Time displacementTime = new Time(); 
//		AgendaEntry lastEventAdded = null;
		
		//Chooses the events
		for (int i = startTime.getHour(); i < 25; i++) {
			String key = String.valueOf(i);	
			
			if (!dayEvents.has(key) || i < nextAvailableTime.getHour())
				continue;
			
			JSONArray events = dayEvents.getJSONArray(key);
			for (int j = 0; j < events.length(); j++) {
				JSONObject eventObj = events.getJSONObject(j);
				AgendaEntry event =  new AgendaEntry(eventObj);
				displacementTime = new Time();
				
				//Gets event start time
				Time eventStartTime = new Time(event.getStartTime());
				
				//Calculate displacement time
				/*if (lastEventAdded != null) {
					Venue currentVenue = lastEventAdded.getVenue();
					displacementTime = currentVenue.calculateDisplacementTimeTo(event.getVenue(), "car");
				}*/
				
				//Event can only be added if it starts after timeForEvent  
				Time timeForEvent = Time.add(nextAvailableTime, displacementTime);
				
				int comparator = Time.compare(timeForEvent, eventStartTime);

				//nextAvailableTime + displacementTime < eventStartTime
				
				//Event starts before next available time and cannot be added.
				if (comparator > 0) {
					break;
				} else {
					schedule.add(event);
					/*if (!eventsAdded.contains(event.getId())) {
						schedule.add(event);
						eventsAdded.add(event.getId());
					}*/
					
					if (comparator == 0)
						nextAvailableTime.setTime(eventObj.getString("endTime"));
				}
								
			}
		}
		
		for (AgendaEntry e: schedule)
			System.out.println(e.toJSON());
		return schedule;
	}

    public class EntryAdapter extends ArrayAdapter<AgendaEntry> {

        private ArrayList<AgendaEntry> items;
        //private Context mContext;
        
        public EntryAdapter(Context context, int textViewResourceId, ArrayList<AgendaEntry> items) {
            super(context, textViewResourceId, items);
            this.items = items;
            //this.mContext = context;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
        	View v = convertView;
            if (v == null) {
                //LayoutInflater vi = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                //v = vi.inflate(R.layout.schedulerow, null);
            }
            
            AgendaEntry item = items.get(position);
            if (item != null) {
                TextView time = (TextView) v.findViewById(R.id.time);
                if (time != null)
                      time.setText(item.getStartTime());

                TextView title = (TextView) v.findViewById(R.id.name);
                if (title != null)
                      title.setText(item.getName());
                
            }
            
            return v;
        }
        
    }

}


